export type ICompareFunction<T> = (a: T, b: T) => number;

export type IEqualsFunction<T> = (a: T, b: T) => boolean;

export type IDiffFunction<T> = (a: T, b: T) => number;

export const DOES_NOT_EXIST = -1;

export enum Compare {
    LESS_THAN = -1,
    BIGGER_THAN = 1,
    EQUALS = 0,
}

export function lesserEquals<T>(a: T, b: T, compareFn: ICompareFunction<T>) {
    const comp = compareFn(a, b);
    return comp === Compare.LESS_THAN || comp === Compare.EQUALS;
}

export function biggerEquals<T>(a: T, b: T, compareFn: ICompareFunction<T>) {
    const comp = compareFn(a, b);
    return comp === Compare.BIGGER_THAN || comp === Compare.EQUALS;
}

export function defaultCompare<T>(a: T, b: T): number {
    if (a === b) {
        return Compare.EQUALS;
    }
    return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN;
}

export function defaultEquals<T>(a: T, b: T): boolean {
    return a === b;
}

export function defaultToString(item: any): string {
    if (item === null) {
        return 'NULL';
    } else if (item === undefined) {
        return 'UNDEFINED';
    } else if (typeof item === 'string' || item instanceof String) {
        return `${item}`;
    }
    return item.toString();
}

export function swap(array: any[], a: number, b: number) {
    /* const temp = array[a];
    array[a] = array[b];
    array[b] = temp; */
    [array[a], array[b]] = [array[b], array[a]];
}

export function reverseCompare<T>(compareFn: ICompareFunction<T>): ICompareFunction<T> {
    return (a, b) => compareFn(b, a);
}

export function defaultDiff<T>(a: T, b: T): number {
    return Number(a) - Number(b);
}

/**
 * 并集：对于给定的两个集合，返回一个包含两个集合中所有元素的新集合
 * 如果你会展开运算符...可以更简单
 */
export function union<T>(setA: Set<T>, setB: Set<T>): Set<T> {
    /* // 方式一
    const unionSet = new Set<T>();
    setA.forEach(value => unionSet.add(value));
    setB.forEach(value => unionSet.add(value));
    return unionSet; */

    // 方式二
    return new Set<T>([...setA, ...setB]);
}

/**
 * 交集：对于给定的两个集合，返回一个包含两个集合中共有元素的新集合
 * 如果集合数据过大，另一个很小，遍历小的会更有效率
 * 如果你会展开运算符...和filter可以更简单，当然遍历少的这条也可以加上
 * @param setA 默认setA会小一些
 * @param setB 当然，我们这里做了优化，不管AB的大小都能有效率地运行
 */
export function intersection<T>(setA: Set<T>, setB: Set<T>): Set<T> {
    /* // 方式一
    const intersectionSet = new Set<T>();
    let smallerSet: Set<T> = setA; // 我们默认遍历小的
    let biggerSet: Set<T> = setB;
    if (setA.size > setB.size) {// 如果B更小就对调
        smallerSet = setB;
        biggerSet = setA;
    }
    smallerSet.forEach(value => {
        if (biggerSet.has(value)) {
            intersectionSet.add(value);
        }
    });
    return intersectionSet; */

    // 方式二
    let smallerSet: Set<T> = setA; // 我们默认遍历小的
    let biggerSet: Set<T> = setB;
    if (setA.size > setB.size) {// 如果B更小就对调
        smallerSet = setB;
        biggerSet = setA;
    }
    return new Set<T>([...smallerSet].filter(x => biggerSet.has(x)));
}

/**
 * 差集：对于给定的两个集合，返回一个包含所有存在于第一个集合且不存在于第二个集合的元素的新集合
 * 如果你会展开运算符...和filter可以更简单
 * @param setA 默认setA会大一些
 * @param setB 毕竟一般会认为是A减去B
 */
export function difference<T>(setA: Set<T>, setB: Set<T>): Set<T> {
    /* // 方式一
    const differenceSet = new Set<T>();
    setA.forEach(value => {
        if (!setB.has(value)) {
            differenceSet.add(value);
        }
    });
    return differenceSet; */

    // 方式二
    return new Set<T>([...setA].filter(x => !setB.has(x)));
}

/**
 * 子集：验证一个给定集合是否是另一个集合的子集
 * 如果你会展开运算符...和every可以更简单
 * @param setA 默认判断A是否是B的子集
 * @param setB
 */
export function isSubsetOf<T>(setA: Set<T>, setB: Set<T>): boolean {
    /* // 方式一
    if (setA.size > setB.size) {
        return false;
    }
    let isSubset: boolean = true;
    setA.forEach(value => {
        if (!setB.has(value)) {
            isSubset = false;
        }
    });
    return isSubset; */

    // 方式二
    return [...setA].every(x => setB.has(x));
}
